package com.lemon.boot.service.impl;

import com.lemon.boot.common.base.BaseServiceImpl;
import com.lemon.boot.common.consts.ApiConst;
import com.lemon.boot.common.enums.RoleKeyEnum;
import com.lemon.boot.common.enums.StatusEnum;
import com.lemon.boot.dao.MenuResourceDAO;
import com.lemon.boot.dto.MenuResourceDTO;
import com.lemon.boot.po.MenuResourcePO;
import com.lemon.boot.po.RolePO;
import com.lemon.boot.po.TenantMenuPO;
import com.lemon.boot.service.IMenuResourceService;
import com.lemon.boot.service.IRoleService;
import com.lemon.boot.vo.TenantMenuResourceVO;
import lombok.extern.log4j.Log4j2;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.groupingBy;

/**
 * 菜单-接口中间表 业务实现类
 *
 * @author 李猛
 * @since 2024-02-11
 */
@Log4j2
@Service
public class MenuResourceServiceImpl extends BaseServiceImpl<MenuResourceDAO, MenuResourcePO, MenuResourceDTO> implements IMenuResourceService {
    @Resource
    @Lazy
    private IRoleService iRoleService;

    @Override
    public List<String> getByUserId(Long userId, Long tenantId, List<Long> roleIdList) {
        Map<String, Object> param = ApiConst.enableStatusAndUnableDelete();
        param.put("userId", userId);
        param.put("tenantId", tenantId);
        param.put("roleIdList", roleIdList);
        List<String> result = this.baseMapper.getByUserId(param);
        if (CollectionUtils.isEmpty(result)) {
            return result;
        }
        return result.stream().map(item -> item.startsWith("/") ? item.substring(1) : item).distinct().collect(Collectors.toList());
    }

    @Override
    @Transactional
    public void setByTenantIdMenuId(Long tenantId, List<TenantMenuPO> tenantMenuList, List<TenantMenuResourceVO> tenantMenuResourceList) {
        //1.根据租户ID查询角色
        List<RolePO> roleList = iRoleService.getByTenantId(tenantId);
        if (CollectionUtils.isEmpty(roleList)) {
            return;
        }

        //2.所有的角色ID
        List<Long> allRoleIdList = roleList.stream().map(RolePO::getId).collect(Collectors.toList());

        //3.判断传入的租户菜单是否为空，如果为空全部删除
        if (CollectionUtils.isEmpty(tenantMenuList)) {
            //3.1.全部删除
            this.update().in("role_id", allRoleIdList).remove();
        } else {
            //3.2已选择的菜单ID
            List<Long> selectMenuIdList = tenantMenuResourceList.stream().filter(TenantMenuResourceVO::isSelected).map(TenantMenuResourceVO::getMenuId).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(selectMenuIdList)) {
                this.update().in("role_id", allRoleIdList).remove();
            } else {
                /*
                TODO
                给所有角色删除 sys_menu_resource
                 */
                //3.3.获取租户菜单ID
                List<Long> tenantMenuIdList = tenantMenuList.stream().filter(item -> item.getMenuId() == null || selectMenuIdList.contains(item.getMenuId())).map(TenantMenuPO::getId).collect(Collectors.toList());

                //3.4.查询已存在的租户菜单ID
                List<MenuResourcePO> menuResourceList = this.query().select("id", "role_id", "tenant_menu_id", "resource_id").in("role_id", allRoleIdList).list();

                //3.5.获取要删除的ID,执行删除
                List<Long> menuResourceIdList = menuResourceList.stream().filter(item -> !tenantMenuIdList.contains(item.getTenantMenuId())).map(MenuResourcePO::getId).collect(Collectors.toList());
                this.removeByIds(menuResourceIdList);

                /*
                 TODO
                 给管理员角色新增 sys_menu_resource
                 */
                //3.6.获取管理员角色ID
                List<Long> adminRoleIdList = roleList.stream().filter(item -> RoleKeyEnum.ADMIN.getRoleKey().equals(item.getRoleKey())).map(RolePO::getId).collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(adminRoleIdList)) {
                    List<MenuResourcePO> menuResources = new ArrayList<>();
                    tenantMenuResourceList.stream().filter(TenantMenuResourceVO::isSelected).forEach(item -> {
                        List<Long> tenantMenuIds = tenantMenuList.stream().filter(menu -> item.getMenuId().equals(menu.getMenuId())).map(TenantMenuPO::getId).distinct().collect(Collectors.toList());
                        if (!CollectionUtils.isEmpty(tenantMenuIds) && tenantMenuIds.size() == 1) {
                            Long menuId = tenantMenuIds.get(0);
                            List<Long> selectResourceList = item.getSelectResourceList();
                            if (!CollectionUtils.isEmpty(selectResourceList)) {
                                for (Long resourceId : selectResourceList) {
                                    for (Long adminRoleId : adminRoleIdList) {
                                        boolean exists = menuResourceList.stream().noneMatch(source ->
                                                Objects.equals(source.getResourceId(), resourceId)
                                                        && Objects.equals(source.getTenantMenuId(), menuId)
                                                        && Objects.equals(source.getRoleId(), adminRoleId));
                                        if (exists) {
                                            menuResources.add(new MenuResourcePO().setResourceId(resourceId).setTenantMenuId(menuId).setRoleId(adminRoleId));
                                        }
                                    }
                                }
                            }
                        }
                    });
                    if (!CollectionUtils.isEmpty(menuResources)) {
                        this.saveBatch(menuResources, Integer.MAX_VALUE);
                    }
                }
            }
        }
    }

    @Override
    public Map<Long, List<Long>> getByGroupTenantMenuId(Long tenantId, List<Long> tenantMenuIdList) {
        //1.获取当前租户的管理员角色
        RolePO rolePO = iRoleService.query().select("id").eq("tenant_id", tenantId).eq(StatusEnum.ENABLE.getColumn(), StatusEnum.ENABLE.getStatus()).eq(RoleKeyEnum.ADMIN.getColumn(), RoleKeyEnum.ADMIN.getRoleKey()).last("limit 1").one();

        //2.查询中间表 sys_menu_resource
        List<MenuResourcePO> menuResourceList = this.query().select("tenant_menu_id", "resource_id").eq("role_id", rolePO.getId()).in("tenant_menu_id", tenantMenuIdList).list();

        //3.分组,并返回
        return menuResourceList
                .stream()
                .collect(groupingBy(MenuResourcePO::getTenantMenuId))
                .entrySet()
                .stream()
                .collect(Collectors.toMap(Map.Entry::getKey, // 保留原始的key
                        entry -> entry
                                .getValue()
                                .stream()
                                .map(MenuResourcePO::getResourceId)
                                .collect(Collectors.toList()) // 转换为List<Long>
                ));
    }
}